using System;
using System.Collections.Generic;

namespace Test.ConsoleProgram.Algorithm.Work
{
    public static class ExtentFunctions
    {
        /// <summary>
        /// string格式有要求，必须是yyyy-MM-dd hh:mm:ss
        /// </summary>
        public static DateTime ToTime(this string timeString) => Convert.ToDateTime(timeString);
    }


    [TestDescription("工作逻辑: 时间值分割")]
    public class Test_DateTimeSplit : AbsBaseTestItem
    {
        public override void OnTest()
        {
            OnExecute(
                "2020-01-01 12:00:00".ToTime(),
                "2020-01-05 12:00:00".ToTime(),
                DateTimeSplit.ESection.Day, 1, new DateTimeSplit.MTime[] {
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 00:00:00".ToTime(),
                        End = "2020-01-01 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 00:00:00".ToTime(),
                        End = "2020-01-02 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-03 00:00:00".ToTime(),
                        End = "2020-01-03 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-04 00:00:00".ToTime(),
                        End = "2020-01-04 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-05 00:00:00".ToTime(),
                        End = "2020-01-05 23:59:59".ToTime(),
                    },
                });

            OnExecute(
                "2020-01-01 19:52:22".ToTime(),
                "2020-01-02 05:00:00".ToTime(),
                DateTimeSplit.ESection.Hour, 1, new DateTimeSplit.MTime[] {
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 19:00:00".ToTime(),
                        End = "2020-01-01 19:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 20:00:00".ToTime(),
                        End = "2020-01-01 20:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 21:00:00".ToTime(),
                        End = "2020-01-01 21:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 22:00:00".ToTime(),
                        End = "2020-01-01 22:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 23:00:00".ToTime(),
                        End = "2020-01-01 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 00:00:00".ToTime(),
                        End = "2020-01-02 00:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 01:00:00".ToTime(),
                        End = "2020-01-02 01:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 02:00:00".ToTime(),
                        End = "2020-01-02 02:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 03:00:00".ToTime(),
                        End = "2020-01-02 03:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 04:00:00".ToTime(),
                        End = "2020-01-02 04:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-02 05:00:00".ToTime(),
                        End = "2020-01-02 05:59:59".ToTime(),
                    },
                });

            OnExecute(
                "2020-01-30".ToTime(),
                "2021-01-30".ToTime(),
                DateTimeSplit.ESection.Month, 1, new DateTimeSplit.MTime[] {
                    new DateTimeSplit.MTime() {
                        Start = "2020-01-01 00:00:00".ToTime(),
                        End = "2020-01-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-02-01 00:00:00".ToTime(),
                        End = "2020-02-29 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-03-01 00:00:00".ToTime(),
                        End = "2020-03-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-04-01 00:00:00".ToTime(),
                        End = "2020-04-30 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-05-01 00:00:00".ToTime(),
                        End = "2020-05-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-06-01 00:00:00".ToTime(),
                        End = "2020-06-30 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-07-01 00:00:00".ToTime(),
                        End = "2020-07-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-08-01 00:00:00".ToTime(),
                        End = "2020-08-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-09-01 00:00:00".ToTime(),
                        End = "2020-09-30 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-10-01 00:00:00".ToTime(),
                        End = "2020-10-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-11-01 00:00:00".ToTime(),
                        End = "2020-11-30 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2020-12-01 00:00:00".ToTime(),
                        End = "2020-12-31 23:59:59".ToTime(),
                    },
                    new DateTimeSplit.MTime() {
                        Start = "2021-01-01 00:00:00".ToTime(),
                        End = "2021-01-31 23:59:59".ToTime(),
                    },
                });
        }

        private void OnExecute(DateTime start, DateTime end,
            DateTimeSplit.ESection section, int step,
            IList<DateTimeSplit.MTime> answers)
        {
            var split = new DateTimeSplit(section, step);
            Assert.TestExe(split.ToSplitList, start, end, answers);
        }
    }

    /// <summary>
    /// 时间值分割帮助类
    /// </summary>
    public class DateTimeSplit
    {
        public class MTime
        {
            public DateTime Start { get; set; }
            public DateTime End { get; set; }
        }

        /// <summary>
        /// 定义分割的部分
        /// </summary>
        public enum ESection
        {
            /// <summary>
            /// 年份
            /// </summary>
            Year,
            /// <summary>
            /// 月份
            /// </summary>
            Month,
            /// <summary>
            /// 日期
            /// </summary>
            Day,
            /// <summary>
            /// 小时
            /// </summary>
            Hour,
            /// <summary>
            /// 分钟
            /// </summary>
            Minute,
            /// <summary>
            /// 秒
            /// </summary>
            Second,
        }

        private readonly ESection section;
        private readonly int stepLength = 1;

        /// <summary>
        /// 初始化定义要分割的部分, 默认步长为 1
        /// </summary>
        /// <param name="section">分割部分</param>
        public DateTimeSplit(ESection section)
        {
            this.section = section;
        }

        /// <summary>
        /// 初始化定义要分割的部分, 步长
        /// </summary>
        /// <param name="section">分割部分</param>
        /// <param name="stepLength">步长</param>
        public DateTimeSplit(ESection section, int stepLength)
        {
            this.section = section;
            this.stepLength = stepLength;
        }

        /// <summary>
        /// 将开始时间与结束时间按指定部分与步长进行分割
        /// </summary>
        /// <param name="start_time">开始时间</param>
        /// <param name="end_time">结束时间</param>
        /// <returns>结果</returns>
        public IList<MTime> ToSplitList(DateTime start, DateTime end)
        {
            if (start > end)
            {
                var center = start;
                start = end;
                end = center;
            }
            IList<MTime> list = new List<MTime>();
            DateTime temp = start;
            while (temp <= end)
            {
                DateTime Start, End;
                switch (section)
                {
                    case ESection.Year:
                        Start = new DateTime(temp.Year, 1, 1, 0, 0, 0);
                        End = Start.AddYears(stepLength).AddSeconds(-1);
                        temp = Start.AddYears(stepLength);
                        break;
                    case ESection.Month:
                        Start = new DateTime(temp.Year, temp.Month, 1, 0, 0, 0);
                        End = Start.AddMonths(stepLength).AddSeconds(-1);
                        temp = Start.AddMonths(stepLength);
                        break;
                    case ESection.Day:
                        Start = new DateTime(temp.Year, temp.Month, temp.Day, 0, 0, 0);
                        End = Start.AddDays(stepLength).AddSeconds(-1);
                        temp = Start.AddDays(stepLength);
                        break;
                    case ESection.Hour:
                        Start = new DateTime(temp.Year, temp.Month, temp.Day, temp.Hour, 0, 0);
                        End = Start.AddHours(stepLength).AddSeconds(-1);
                        temp = Start.AddHours(stepLength);
                        break;
                    case ESection.Minute:
                        Start = new DateTime(temp.Year, temp.Month, temp.Day, temp.Hour, temp.Minute, 0);
                        End = Start.AddMinutes(stepLength).AddSeconds(-1);
                        temp = Start.AddMinutes(stepLength);
                        break;
                    case ESection.Second:
                        Start = new DateTime(temp.Year, temp.Month, temp.Day, temp.Hour, temp.Minute, temp.Second);
                        End = Start.AddSeconds(stepLength).AddMilliseconds(-1);
                        temp = Start.AddSeconds(stepLength);
                        break;
                    default:
                        throw new Exception("未定义错误时间部分枚举!");
                }
                list.Add(new MTime()
                {
                    Start = Start,
                    End = End,
                });
            }
            return list;
        }
    }
}
